home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / pmode / exc_dx02 / uasm.c < prev    next >
C/C++ Source or Header  |  1994-08-03  |  20KB  |  715 lines

  1. /* This is the exc-32 Debugger disassembler.  */
  2.  
  3. /*
  4.   MMURTL Operating System Source Code
  5.   Copyright 1991,1992,1993, Richard A. Burgess
  6.   ALL RIGHTS RESERVED
  7.   Version x0.8
  8. */
  9.  
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <stdarg.h>
  13. #include "uasm.h"
  14.  
  15. /* Handy type defines */
  16.  
  17. #define U32  unsigned long
  18. #define U16  unsigned short
  19. #define U8   unsigned char
  20. #define S32  signed   long
  21. #define S16  signed   short
  22. #define S8   signed   char
  23. #define SEGSIZE  32
  24.  
  25. /* Protypes */
  26.  
  27. U8    getbyte (void);
  28. U8    modrm   (void);
  29. U8    sib     (void);
  30. int   bytes   (char c);
  31. void  ohex    (char c, int extend, int optional, int defsize);
  32. void  reg_name(U8 which, char size);
  33. void  escape  (char c, char t);
  34. void  decode  (char *s);
  35. void  do_sib  (int m);
  36. void  do_modrm(char t);
  37.  
  38.  
  39.  
  40. /*
  41.   The Intel 386 DX Programmer's Reference Manual provides a table that
  42.   uses the following codes to assist in disassembly of 386 code (page A-3).
  43.   The letters below are the same as the codes in the manual.  The ~ (tilde)
  44.   is an escape character to signify expansion of the codes is
  45.   required when the string is being output.
  46.  
  47.   Tilde tokens in strings:
  48.  
  49.      First char after '~':
  50.    A - Direct address
  51.    C - Reg of R/M picks control register
  52.    D - Reg of R/M picks debug register
  53.    E - R/M picks operand
  54.    F - Flag register
  55.    G - Reg of R/M selects a general register
  56.    I - Immediate data
  57.    J - Relative IP offset
  58.    M - R/M picks memory
  59.    O - No R/M, offset only
  60.    R - Mod of R/M picks register only
  61.    S - Reg of R/M picks segment register
  62.    T - reg of R/M picks test register
  63.    X - DS:ESI
  64.    Y - ES:EDI
  65.    2 - prefix of two-byte opcode
  66.    e - put in 'e' if use32 (second char is part of reg name)
  67.        put in 'w' for use16 or 'd' for use32 (second char is 'w')
  68.    f - Floating point (second char is esc value)
  69.    g - do R/M group 'n'
  70.    p - prefix
  71.    s - Size override (second char is a,o)
  72.  
  73.      Second char after '~':
  74.    a - Two words in memory (BOUND)
  75.    b - Byte
  76.    c - Byte or word
  77.    d - DWord
  78.    p - 32 or 48 bit pointer
  79.    s - Six byte pseudo-descriptor
  80.    v - Word or DWord
  81.    w - Word
  82.    1-8 - group number, esc value, etc
  83. */
  84.  
  85. char *opmap1[] = {
  86. /* 0 */
  87.   "ADD ~Eb,~Gb", "ADD ~Ev,~Gv",  "ADD ~Gb,~Eb", "ADD ~Gv,~Ev",
  88.   "ADD AL,~Ib",  "ADD ~eAX,~Iv", "PUSH ES",     "POP ES",
  89.   "OR ~Eb,~Gb",  "OR ~Ev,~Gv",   "OR ~Gb,~Eb",  "OR ~Gv,~Ev",
  90.   "OR AL,~Ib",   "OR ~eAX,~Iv",  "PUSH CS",     "~2 ",
  91. /* 1 */
  92.   "ADC ~Eb,~Gb", "ADC ~Ev,~Gv",  "ADC ~Gb,~Eb", "ADC ~Gv,~Ev",
  93.   "ADC AL,~Ib",  "ADC ~eAX,~Iv", "PUSH SS",     "POP SS",
  94.   "SBB ~Eb,~Gb", "SBB ~Ev,~Gv",  "SBB ~Gb,~Eb", "SBB ~Gv,~Ev",
  95.   "SBB AL,~Ib",  "SBB ~eAX,~Iv", "PUSH DS",     "POP DS",
  96. /* 2 */
  97.   "AND ~Eb,~Gb", "AND ~Ev,~Gv",  "AND ~Gb,~Eb", "AND ~Gv,~Ev",
  98.   "AND AL,~Ib",  "AND ~eAX,~Iv", "~pE",         "DAA",
  99.   "SUB ~Eb,~Gb", "SUB ~Ev,~Gv",  "SUB ~Gb,~Eb", "SUB ~Gv,~Ev",
  100.   "SUB AL,~Ib",  "SUB ~eAX,~Iv", "~pC",         "DAS",
  101. /* 3 */
  102.   "XOR ~Eb,~Gb", "XOR ~Ev,~Gv",  "XOR ~Gb,~Eb", "XOR ~Gv,~Ev",
  103.   "XOR AL,~Ib",  "XOR ~eAX,~Iv", "~pS",         "AAA",
  104.   "CMP ~Eb,~Gb", "CMP ~Ev,~Gv",  "CMP ~Gb,~Eb", "CMP ~Gv,~Ev",
  105.   "CMP AL,~Ib",  "CMP ~eAX,~Iv", "~pD",         "AAS",
  106. /* 4 */
  107.   "INC ~eAX",    "INC ~eCX",     "INC ~eDX",    "INC ~eBX",
  108.   "INC ~eSP",    "INC ~eBP",     "INC ~eSI",    "INC ~eDI",
  109.   "DEC ~eAX",    "DEC ~eCX",     "DEC ~eDX",    "DEC ~eBX",
  110.   "DEC ~eSP",    "DEC ~eBP",     "DEC ~eSI",    "DEC ~eDI",
  111. /* 5 */
  112.   "PUSH ~eAX",   "PUSH ~eCX",    "PUSH ~eDX",   "PUSH ~eBX",
  113.   "PUSH ~eSP",   "PUSH ~eBP",    "PUSH ~eSI",   "PUSH ~eDI",
  114.   "POP ~eAX",    "POP ~eCX",     "POP ~eDX",    "POP ~eBX",
  115.   "POP ~eSP",    "POP ~eBP",     "POP ~eSI",    "POP ~eDI",
  116. /* 6 */
  117.   "PUSHA",       "POPA",         "BOUND ~Gv,~Ma", "ARPL ~Ew,~Rw",
  118.   "~pF",         "~pG",          "~so",           "~sa",
  119.   "PUSH ~Iv",    "IMUL ~Gv,~Ev*~Iv", "PUSH ~Ib",  "IMUL ~Gv,~Ev*~Ib",
  120.   //                   !! ^was =                        !! ^was =
  121.   "INSB ~Yb,DX", "INS~ew ~Yv,DX", "OUTSB DX,~Xb", "OUTS~ew DX,~Xv",
  122. /* 7 */
  123.   "JO ~Jb",      "JNO ~Jb",       "JNC ~Jb",      "JC ~Jb",
  124.   "JZ ~Jb",      "JNZ ~Jb",       "JBE ~Jb",      "JNBE ~Jb",
  125.   "JS ~Jb",      "JNS ~Jb",       "JPE ~Jb",      "JPO ~Jb",
  126.   "JL ~Jb",      "JGE ~Jb",       "JLE ~Jb",      "JG ~Jb",
  127. /* 8 */
  128.   "~g1 ~Eb,~Ib",  "~g1 ~Ev,~Iv",  "MOV AL,~Ib",   "~g1 ~Ev,~Ib",
  129.   "TEST ~Eb,~Gb", "TEST ~Ev,~Gv", "XCHG ~Eb,~Gb", "XCHG ~Ev,~Gv",
  130.   "MOV ~Eb,~Gb",  "MOV ~Ev,~Gv",  "MOV ~Gb,~Eb",  "MOV ~Gv,~Ev",
  131.   "MOV ~Ew,~Sw",  "LEA ~Gv,~M ",  "MOV ~Sw,~Ew",  "POP ~Ev",
  132. /* 9 */
  133.   "NOP",            "XCHG ~eAX,~eCX", "XCHG ~eAX,~eDX", "XCHG ~eAX,~eBX",
  134.   "XCHG ~eAX,~eSP", "XCHG ~eAX,~eBP", "XCHG ~eAX,~eSI", "XCHG ~eAX,~eDI",
  135.   "CBW",            "CDW",            "CALL ~Ap",       "FWAIT",
  136.   "PUSH ~eflags",   "POP ~eflags",    "SAHF",           "LAHF",
  137. /* a */
  138.   "MOV AL,~Ov",     "MOV ~eAX,~Ov",     "MOV ~Ov,al",    "MOV ~Ov,~eAX",
  139.   "MOVSB ~Xb,~Yb",  "MOVS~ew ~Xv,~Yv",  "CMPSB ~Xb,~Yb", "CMPS~ew ~Xv,~Yv",
  140.   "TEST AL,~Ib",    "TEST ~eAX,~Iv",    "STOSB ~Yb,AL",  "STOS~ew ~Yv,~eAX",
  141.   "LODSB AL,~Xb",   "LODS~ew ~eAX,~Xv", "SCASB AL,~Xb",  "SCAS~ew ~eAX,~Xv",
  142. /* b */
  143.   "MOV AL,~Ib",   "MOV CL,~Ib",   "MOV DL,~Ib",   "MOV BL,~Ib",
  144.   "MOV AH,~Ib",   "MOV CH,~Ib",   "MOV DH,~Ib",   "MOV BH,~Ib",
  145.   "MOV ~eAX,~Iv", "MOV ~eCX,~Iv", "MOV ~eDX,~Iv", "MOV ~eBX,~Iv",
  146.   "MOV ~eSP,~Iv", "MOV ~eBP,~Iv", "MOV ~eSI,~Iv", "MOV ~eDI,~Iv",
  147. /* c */
  148.   "~g2 ~Eb,~Ib",   "~g2 ~Ev,~Ib",  "RET ~Iw",      "RET",
  149.   "LES ~Gv,~Mp",   "LDS ~Gv,~Mp",  "MOV ~Eb,~Ib",  "MOV ~Ev,~Iv",
  150.   "ENTER ~Iw,~Ib", "LEAVE",        "RETF ~Iw",     "RETF",
  151.   "INT 3",         "INT ~Ib",      "INTO",         "IRETD",
  152. /* d */
  153.   "~g2 ~Eb,1", "~g2 ~Ev,1", "~g2 ~Eb,cl", "~g2 ~Ev,cl",
  154.   "AAM", "AAD", 0, "XLAT",
  155.  
  156. /*
  157.   "ESC 0,~Ib", "ESC 1,~Ib", "ESC 2,~Ib", "ESC 3,~Ib",
  158.   "ESC 4,~Ib", "ESC 5,~Ib", "ESC 6,~Ib", "ESC 7,~Ib",
  159. */
  160.  
  161.   "~f0", "~f1", "~f2", "~f3",
  162.   "~f4", "~f5", "~f6", "~f7",
  163.  
  164. /* e */
  165.   "LOOPNE ~Jb", "LOOPE ~Jb", "LOOP ~Jb", "JCXZ ~Jb",
  166.   "IN AL,~Ib", "IN ~eAX,~Ib", "OUT ~Ib,AL", "OUT ~Ib,~eAX",
  167.   "CALL ~Jv", "JMP ~Jv", "JMP ~Ap", "JMP ~Jb",
  168.   "IN AL,DX", "IN ~eAX,DX", "OUT DX,AL", "OUT DX,~eAX",
  169. /* f */
  170.   "LOCK~p ", 0, "REPNE~p ", "REP(e)~p ",
  171.   "HLT", "CMC", "~g3", "~g0",
  172.   "CLC", "STC", "CLI", "STI",
  173.   "CLD", "STD", "~g4", "~g5"
  174.   };
  175.  
  176. char *SecOp00[] = {
  177. /* 0 */
  178.   "~g6", "~g7", "LAR ~Gv,~Ew", "LSL ~Gv,~Ew", 0, 0, "CLTS", 0,
  179.   0, 0, 0, 0, 0, 0, 0, 0 };
  180.  
  181. char *SecOp20[] = {
  182. /* 2 */
  183.   "MOV ~Rd,~Cd", "MOV ~Rd,~Dd", "MOV ~Cd,~Rd", "MOV ~Dd,~Rd",
  184.   "MOV ~Rd,~Td", 0, "MOV ~Td,~Rd", 0,
  185.   0, 0, 0, 0, 0, 0, 0, 0};
  186.  
  187. char *SecOp80[] = {
  188.   "JO ~Jv", "JNO ~Jv", "JC ~Jv", "JNC ~Jv",
  189.   "JZ ~Jv", "JNZ ~Jv", "JBE ~Jv", "JNBE ~Jv",
  190.   "JS ~Jv", "JNS ~Jv", "JPE ~Jv", "JPO ~Jv",
  191.   "JL ~Jv", "JGE ~Jv", "JLE ~Jv", "JG ~Jv",
  192. /* 9 */
  193.   "SETO ~Eb", "SETNO ~Eb", "SETNC ~Eb", "SETC ~Eb",
  194.   "SETZ ~Eb", "SETNZ ~Eb", "SETBE ~Eb", "SETNBE ~Eb",
  195.   "SETS ~Eb", "SETNS ~Eb", "SETP ~Eb", "SETNP ~Eb",
  196.   "SETL ~Eb", "SETGE ~Eb", "SETLE ~Eb", "SETG ~Eb",
  197. /* a */
  198.   "PUSH FS",          "POP FS",          0,          "BT ~Ev,~Gv",
  199.   "SHLD ~Ev,~Gv,~Ib", "SHLD ~Ev,~Gv,cl", 0,           0,
  200.   "PUSH GS",          "POP GS",          0,          "BTS ~Ev,~Gv",
  201.   "SHRD ~Ev,~Gv,~Ib", "SHRD ~Ev,~Gv,cl", 0,          "IMUL ~Gv,~Ev",
  202. /* b */
  203.   0, 0, "LSS ~Mp", "BTR ~Ev,~Gv",
  204.   "LFS ~Mp", "LGS ~Mp", "MOVZX ~Gv,~Eb", "MOVZX ~Gv,~Ew",
  205.   0, 0, "~g8 ~Ev,~Ib", "BTC ~Ev,~Gv",
  206.   "BSF ~Gv,~Ev", "BSR~Gv,~Ev", "MOVSX ~Gv,~Eb", "MOVSX ~Gv,~Ew",
  207.   };
  208. /* NOTE: Second byte of 2 byte OpCodes are Invalid if over 0xBF */
  209.  
  210.  
  211. char *groups[9][8] = {   /* group 0 is group 3 for ~Ev set */
  212.   { "TEST ~Ev,~Iv", "TEST ~Ev,~Iv,", "NOT ~Ev",      "NEG ~Ev",
  213.     "MUL ~eAX,~Ev", "IMUL ~eAX,~Ev", "DIV ~eAX,~Ev", "IDIV ~eAX,~Ev" },
  214.   { "ADD", "OR", "ADC", "SBB", "AND", "SUB", "XOR", "CMP" },
  215.   { "ROL", "ROR","RCL", "RCR", "SHL", "SHR", "SHL", "SAR" },
  216.   { "TEST ~Eb,~Ib", "TEST ~Eb,~Ib,", "NOT ~Eb", "NEG ~Eb",
  217.     "MUL AL,~Eb", "IMUL AL,~Eb", "DIV AL,~Eb", "IDIV AL,~Eb" },
  218.   { "INC ~Eb", "DEC ~Eb", 0, 0, 0, 0, 0, 0 },
  219.   { "INC ~Ev", "DEC ~Ev", "CALL ~Ev", "CALL ~Ep",
  220.     "JMP ~Ev", "JMP ~Ep", "PUSH ~Ev", 0 },
  221.   { "SLDT ~Ew", "STR ~Ew", "LLDT ~Ew", "LTR ~Ew",
  222.     "VERR ~Ew", "VERW ~Ew", 0, 0 },
  223.   { "SGDT ~Ms", "SIDT ~Ms", "LGDT ~Ms", "LIDT ~Ms",
  224.     "SMSW ~Ew", 0, "LMSW ~Ew", 0 },
  225.   { 0, 0, 0, 0, "BT", "BTS", "BTR", "BTC" }
  226.  };
  227.  
  228. /* for display */
  229. char *seg_names[]= {"ES","CS","SS","DS","FS","GS"};
  230. char *breg_names[]={"AL","CL","DL","BL","AH","CH","DH","BH" };
  231. char *wreg_names[]={"AX","CX","DX","BX","SP","BP","SI","DI" };
  232. char *dreg_names[]={"EAX","ECX","EDX","EBX","ESP","EBP","ESI","EDI" };
  233.  
  234. S16 prefix;
  235. U8  modrmv;
  236. S8  fmodrmv;
  237. U8  sibv;
  238. S8  fsibv;
  239. S16 opsize;
  240. U8  *addrIn;
  241. void *disasm_outAdr;
  242.  
  243.  
  244. static char  outBuf[200];
  245. static char *outPtr = outBuf;
  246.  
  247. static void outf(char *text,...)
  248. {
  249.   va_list args;
  250.   va_start(args,text);
  251.   vsprintf (outPtr,text,args);
  252.   outPtr = strchr(outBuf,0);
  253.   va_end(args);
  254. }
  255.  
  256.  
  257. /*****************************************************
  258. Gets a byte to disassemble and update addrIn.
  259. ******************************************************/
  260.  
  261. U8 getbyte(void)
  262. {
  263.   return *addrIn++;
  264. }
  265.  
  266.  
  267. /*************************************************/
  268. /* Get Mod/RM field byte for current instruction */
  269.  
  270. U8 modrm(void)
  271. {
  272.   if (!fmodrmv)
  273.   {
  274.     modrmv = getbyte();
  275.     fmodrmv = 1;
  276.   }
  277.   return modrmv;
  278. }
  279.  
  280.  
  281. /*******************************************************/
  282. /* Get 'scale-index-base' byte for current instruction */
  283.  
  284. U8 sib(void)
  285. {
  286.   if (!fsibv)
  287.   {
  288.     sibv = getbyte();
  289.     fsibv = 1;
  290.   }
  291.   return sibv;
  292. }
  293.  
  294. /**********************************************************/
  295. /* The register is encode as bit 3,4,5 in the byte.
  296.    xxRRRxxx
  297.    This macro extracts it.  Used in several places.
  298. */
  299.  
  300. #define reg(a)    (((a)>>3)&7)
  301.  
  302. /*------------------------------------------------------------------------*/
  303.  
  304. /*------------------------------------------------------------------------*/
  305. /* Determines how many bytes left in the instruction from the
  306.   letter in the table (which is passed in here).
  307. */
  308.  
  309. int bytes(char c)
  310. {
  311.   switch (c)
  312.   {
  313.     case 'b':
  314.       return 1;
  315.     case 'w':
  316.       return 2;
  317.     case 'd':
  318.       return 4;
  319.     case 'v':
  320.       if (opsize == 32)
  321.            return 4;
  322.       else return 2;
  323.   }
  324.   return 0;
  325. }
  326.  
  327. /**************************************************************
  328. Get the correct number of bytes for immediate data from the
  329. code stream and output it as hex.
  330. ***************************************************************/
  331.  
  332. void ohex(char c, int extend, int optional, int defsize)
  333. {
  334.   int n, s, i;
  335.   long int *x;
  336.   unsigned char buf[6];
  337.  
  338.   n=0;
  339.   s=0;
  340.   x=NULL;
  341.  
  342.   switch (c)
  343.   {
  344.     case 'a': break;
  345.     case 'b': n = 1;   /* byte */
  346.               break;
  347.     case 'w': n = 2;   /* word */
  348.               break;
  349.     case 'd': n = 4;   /* dword */
  350.               break;
  351.     case 's': n = 6;   /* fword */
  352.               break;
  353.     case 'c':
  354.     case 'v': if (defsize == 32)
  355.                    n = 4;
  356.               else n = 2;
  357.               break;
  358.     case 'p': if (defsize == 32)   /* 32 or 48 bit pointer */
  359.                    n = 6;
  360.               else n = 4;
  361.               s = 1;
  362.               break;
  363.   }
  364.  
  365.   for (i=0; i<n; i++)
  366.      buf[i] = getbyte();
  367.  
  368.   /* sign extend the value into a U32 */
  369.  
  370.   for (; i<extend; i++)
  371.      buf[i] = (buf[i-1] & 0x80) ? 0xff : 0;
  372.  
  373.   
  374.   if (n <= 4)         /* !! make displacements negative, GV */
  375.   {
  376.     x = (long int*)&buf;
  377.     if (*x < 0)
  378.     {
  379.       outf("-%02X",-*x);
  380.       return;
  381.     }
  382.   }
  383.  
  384.   if (s)        /* outputs the segment value of FAR pointer */
  385.   {
  386.     outf("%02X%02X",buf[n-1],buf[n-2]);
  387.     n -= 2;
  388.   }
  389.  
  390.   if (extend > n)
  391.   {
  392.     if (!optional)
  393.        outf("+");
  394.     n = 4;
  395.   }
  396.   switch (n)
  397.   {
  398.     case 1: outf("%02X",buf[0]);
  399.             break;
  400.     case 2: outf("%02X%02X",buf[1],buf[0]);
  401.             break;
  402.     case 4: outf("%02X%02X%02X%02X",buf[3],buf[2],buf[1],buf[0]);
  403.             break;
  404.   }
  405. }
  406.  
  407. /*------------------------------------------------------------------------*/
  408.  
  409. void reg_name(U8 which, char size)
  410. {
  411.   if (size == 'F')
  412.   {
  413.     outf( "st(%d)",which);
  414.     return;
  415.   }
  416.   if (((size == 'v') && (opsize == 32)) || (size == 'd'))
  417.   {
  418.     outf("E");
  419.   }
  420.   if (size == 'b')
  421.   {
  422.     outf( "%s", breg_names[which]);
  423.   }
  424.   else
  425.   {
  426.     outf( "%s", wreg_names[which]);
  427.   }
  428. }
  429.  
  430. /******************************************************************
  431.    This takes in two chars that represent part of the op code and
  432.    puts out the proper text to match what the letter represents.
  433.    c is the first char after the tilde and t is next one. See
  434.    opcode1[] strings for what the chars mean.
  435. *******************************************************************/
  436.  
  437. void escape(char c, char t)
  438. {
  439.   S32 delta, vals;
  440.   U8  b2;
  441.   S8  valsb;
  442.   S16 valsw;
  443.  
  444.   switch (c)
  445.   {
  446.     case 'A':                             /* Direct Address */
  447.         ohex(t,4,0,32);
  448.         break;
  449.     case 'C':                             /* Reg of R/M picks control reg */
  450.         outf("CR%d",reg(modrm()));
  451.         break;
  452.     case 'D':                             /* Reg of R/M pick debug reg */
  453.         outf("DR%d",modrm());
  454.         break;
  455.     case 'E':                             /* R/M picks operand */
  456.         do_modrm(t);
  457.         break;
  458.     case 'G':                             /* Reg of R/M picks general reg */
  459.         if (t == 'F')
  460.              reg_name((modrm()&7),t);
  461.         else reg_name(reg(modrm()),t);
  462.         break;
  463.     case 'I':                             /* Immediate data */
  464.         ohex(t,0,0,opsize);
  465.         break;
  466.     case 'J':                             /* Relative IP offset */
  467.         switch (bytes(t))
  468.         {
  469.           case 1:
  470.             valsb = getbyte();        /* must remain signed! */
  471.             vals = valsb;
  472.             break;
  473.           case 2:
  474.             valsb = getbyte();        /*RAB  Made SIGNEd bytes/Words */
  475.             valsw = getbyte()<<8;
  476.             vals = valsw + valsb;
  477.             break;
  478.           case 4:
  479.             vals = getbyte();
  480.             vals |= getbyte() << 8;
  481.             vals |= getbyte() << 16;
  482.             vals |= getbyte() << 24;
  483.             break;
  484.         }
  485.         delta = (S32) (addrIn + vals);
  486.         outf( "%X",delta);
  487.         break;
  488.     case 'M':                             /* R/M picks memory */
  489.         do_modrm(t);
  490.         break;
  491.     case 'O':                             /* NO R/M, Offset only */
  492.         decode("~p:[");
  493.         ohex(t, 4, 0, 32);
  494.         outf("]");
  495.         break;
  496.     case 'R':                             /* Mod of R/M pick REG only */
  497.         do_modrm(t);
  498.         break;
  499.     case 'S':                             /* Reg of R/M picks seg reg */
  500.         outf( "%s", seg_names[reg(modrm())]);
  501.         break;
  502.     case 'T':                             /* Reg of R/M picks test reg */
  503.         outf( "TR%d",modrm());
  504.         break;
  505.     case 'X':                             /* DS:ESI */
  506.         outf("DS:[ESI]");
  507.         break;
  508.     case 'Y':                             /* ES:EDI */
  509.         outf("ES:[EDI]");
  510.         break;
  511.     case '2':                             /* Prefix of 2 byte opcode */
  512.         b2 = getbyte();
  513.         if (b2 < 0x10)
  514.             decode(SecOp00[b2]);
  515.         else if ((b2 > 0x1F) && (b2 < 0x30))
  516.             decode(SecOp20[b2-0x20]);
  517.         else if ((b2 > 0x7F) && (b2 < 0xC0))
  518.             decode(SecOp80[b2-0x80]);
  519.         else
  520.             outf("<bogus>");
  521.         break;
  522.     case 'e':                 /*  t is part of reg name */
  523.         if (opsize == 32)
  524.         {
  525.           if (t == 'w')          /* put out "d" if t is "w" on 32 bit opsize */
  526.                outf("D");
  527.           else outf("E%c",t);  /* put out "E". if t = "w" then put t */
  528.         }
  529.         else outf("%c",t);
  530.         break;
  531.     case 'f':                /* floating point */
  532.         outf("<Float Op>");
  533.  
  534. /*        floating_point(t-'0');  */
  535.  
  536.         break;
  537.     case 'g':                             /* do R/M group 'n' */
  538.         decode(groups[t-'0'][reg(modrm())]);
  539.         break;
  540.     case 'p':                             /* Segment prefix */
  541.         switch (t)
  542.         {
  543.           case 'C':                       /* CS */
  544.           case 'D':                       /* DS */
  545.           case 'E':                       /* ES */
  546.           case 'F':                       /* FS */
  547.           case 'G':                       /* GS */
  548.           case 'S':                       /* SS */
  549.             prefix = t;
  550.             decode(opmap1[getbyte()]);
  551.             break;
  552.           case ':':
  553.             if (prefix)
  554.                 outf("%cS:",prefix);
  555.             break;
  556.           case ' ':
  557.             decode(opmap1[getbyte()]);
  558.             break;
  559.         }
  560.         break;
  561.     case 's':                                /* Size override */
  562.         if (t=='o')                         /* o is operand */
  563.         {
  564.           opsize = 48 - opsize;
  565.           decode(opmap1[getbyte()]);
  566.           }
  567.         break;
  568.   }
  569. }
  570.  
  571.  
  572. /******************************************
  573. This expands and outputs the instruction
  574. string passed in if it finds the escape
  575. character (tilde).
  576. ******************************************/
  577.  
  578. void decode(char *s)
  579. {
  580.   char c;
  581.  
  582.   if (s == 0)                   /* if NULL pointer, then it's BAD */
  583.      outf("<invalid>");
  584.  
  585.   while ((c = *s++) != 0)       /* put next char in c */
  586.   {
  587.     if (c == '~')               /* if c is ~ then ESCAPE */
  588.     {
  589.       c = *s++;                 /* get letter representing value */
  590.       escape(c, *s++);
  591.     }
  592.     else
  593.       if (c == ' ')              /* space */
  594.            outf(" ");
  595.       else outf("%c",c);       /* else put out the char found! */
  596.   }
  597. }
  598.  
  599.  
  600.  
  601. /* outputs 'scale-index-base' instructions */
  602.  
  603. void do_sib(int m)
  604. {
  605.   int s, i, b;
  606.   s = ((sib()) >> 6) & 7;        /* SSxxxxxx Scale */
  607.   i = ((sib()) >> 3) & 7;        /* xxIIIxxx Index */
  608.   b = sib() & 7;                /* xxxxxBBB Base  */
  609.   switch (b)
  610.   {
  611.     case 0: decode("~p:[EAX"); break;
  612.     case 1: decode("~p:[ECX"); break;
  613.     case 2: decode("~p:[EDX"); break;
  614.     case 3: decode("~p:[EBX"); break;
  615.     case 4: decode("~p:[ESP"); break;
  616.     case 5:
  617.       if (m == 0)
  618.       {
  619.         decode("~p:[");
  620.         ohex('d', 4, 0, 32);
  621.       }
  622.       else decode("~p:[EBP");
  623.       break;
  624.     case 6: decode("~p:[ESI"); break;
  625.     case 7: decode("~p:[EDI"); break;
  626.   }
  627.   switch (i)
  628.   {
  629.     case 0: outf("+EAX"); break;
  630.     case 1: outf("+ECX"); break;
  631.     case 2: outf("+EDX"); break;
  632.     case 3: outf("+EBX"); break;
  633.     case 4: break;
  634.     case 5: outf("+EBP"); break;
  635.     case 6: outf("+ESI"); break;
  636.     case 7: outf("+EDI"); break;
  637.   }
  638.   if (i != 4)
  639.     switch (s)
  640.     {
  641.       case 0: break;
  642.       case 1: outf("*2"); break;
  643.       case 2: outf("*4"); break;
  644.       case 3: outf("*8"); break;
  645.  
  646.     }
  647. }
  648.  
  649. /*------------------------------------------------------------------------*/
  650. void do_modrm(char t)
  651. {
  652.   int m;
  653.   int r;
  654.  
  655.   m = ((modrm()) >> 6) & 7;
  656.   r = modrm() & 7;
  657.  
  658.   if (m == 3)
  659.   {
  660.     reg_name(r,t);
  661.     return;
  662.   }
  663.   if ((m == 0) && (r == 5))
  664.   {
  665.     decode("~p:[");
  666.     ohex('d',4,0,32);
  667.     outf("]");
  668.     return;
  669.   }
  670.  
  671.   if (r != 4)
  672.     decode("~p:[");
  673.  
  674.   switch (r)
  675.     {
  676.       case 0: outf("EAX"); break;
  677.       case 1: outf("ECX"); break;
  678.       case 2: outf("EDX"); break;
  679.       case 3: outf("EBX"); break;
  680.       case 4: do_sib(m);   break;
  681.       case 5: outf("EBP"); break;
  682.       case 6: outf("ESI"); break;
  683.       case 7: outf("EDI"); break;
  684.   }
  685.   switch (m)
  686.   {
  687.     case 1: ohex('b',4,0,32);
  688.             break;
  689.     case 2: outf("+");
  690.             ohex('v',4,0,32);
  691.             break;
  692.   }
  693.   outf("]");
  694. }
  695.  
  696. /***********************************************
  697.   This disassembles one instruction each time it
  698.   is called.
  699. ************************************************/
  700.  
  701. char * disassemble(void * addr)
  702. {
  703.   prefix  = 0;
  704.   fmodrmv = 0;
  705.   fsibv   = 0;
  706.   opsize  = SEGSIZE;  /* default operand size is DWORD */
  707.   addrIn  = addr;
  708.   outPtr  = (char*)&outBuf;
  709.  
  710.   decode(opmap1[getbyte()]);    /* decode instruction and output */
  711.   disasm_outAdr = (void*)addrIn;
  712.  
  713.   return outBuf;
  714. }
  715.